# ---JD Stock Telent---

import datetime
import Core.IO as IO
import Core.MongoDB as MongoDB
import Core.Gadget as Gadget
import Core.Algorithm as Algorithm
#import Core.MarketStyle as MarketStyle
# import Algorithm
import math
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import matplotlib.dates as mdate
import Core.Gadget as gadget
import time


def ProcessDateTime(strDateTime):
    pass

def LoadPortfolio():
    header, table = IO.ReadCSVFile("D:/Data/JDStockTalent/Portfolio.csv")
    #
    count = 0
    for data in table:
        count = count + 1
        #
        portfolioDoc = {}
        id = data[header["id"]]
        #
        portfolioDoc["UserName"] = data[header["name"]]
        portfolioDoc["Name"] = id
        portfolioDoc["Type"] = float(data[header["type"]])
        # portfolioDoc["CreatedTime"] = data[header["created_time"]]
        portfolioDoc["Pin"] = data[header["pin"]]
        portfolioDoc["Yn"] = float(data[header["yn"]])
        portfolioDoc["Disabled"] = float(data[header["disabled"]])
        portfolioDoc["Key"] = id
        database.upsert("Talent", "Portfolio", {"Key": portfolioDoc["Key"]}, portfolioDoc)

def LoadAccount():
    header, table = IO.ReadCSVFile("D:/Data/JDStockTalent/Account2.csv")
    #
    count = 0
    for data in table:
        count = count + 1
        if count < 58812:
            continue
        # portfolio = data[header["user_pin"]]
        # type = data[header["type"]]
        id = data[header["package_id"]]
        dt = data[header["value_date"]]
        #
        #print(str(count) + " " + id)
        if dt == "null":
            continue
        #
        dirtyDT = dt.split(" ")
        dt = dirtyDT[0]
        localDateTime = Gadget.ParseDateTime(dt, "%Y-%m-%d")
        localDateTime = localDateTime + datetime.timedelta(hours=15)
        stdDateTime = Gadget.ToUTCDateTime(localDateTime)
        strDateTime = Gadget.ToDateTimeString(localDateTime)

        #
        accountDoc = {}
        accountDoc["Portfolio"] = id
        accountDoc["StdDateTime"] = stdDateTime
        accountDoc["Value"] = float(data[header["value"]])
        accountDoc["ProfitLoss"] = float(data[header["income_d"]])
        accountDoc["Cash"] = 0.0
        accountDoc["DailyReturn"] = float(data[header["return_rate_d"]])
        accountDoc["UnitNetValue"] = 1.0
        accountDoc["Key"] = id + "_" + strDateTime

        # --- Insert Database---
        database.upsert("Talent", "Account", {"Key": accountDoc["Key"]}, accountDoc)
        kkwood = 0

def LoadTrade():
    header, table = IO.ReadCSVFile("D:/Data/JDStockTalent/Trade2.csv")
    #
    count = 0
    for data in table:
        count = count + 1
        #
        tradeDoc = {}
        portfolio = data[header["package_id"]]
        fullcode = data[header["stock_code"]]
        market = fullcode[:2]
        code = fullcode[2:]
        symbol = code + "." + market
        #
        #print(str(count) + " " + portfolio)
        #
        dt = data[header["trade_time"]]
        localDateTime = Gadget.ParseDateTime(dt, "%Y-%m-%d %H:%M:%S")
        stdDateTime = Gadget.ToUTCDateTime(localDateTime)
        strDateTime = Gadget.ToDateTimeString(localDateTime)

        #
        tradeDoc["Portfolio"] = portfolio
        tradeDoc["Symbol"] = symbol
        #
        qty = float(data[header["stock_number_to"]]) - float(data[header["stock_number_from"]])
        if qty >= 0:
            side = "Buy"
        else:
            side = "Sell"
        tradeDoc["Side"] = side
        tradeDoc["Qty"] = qty
        tradeDoc["Price"] = float(data[header["price"]])
        tradeDoc["CashFlow"] = -1 * qty * tradeDoc["Price"]
        #
        tradeDoc["Cost"] = float(data[header["cost_price"]])
        tradeDoc["StdDateTime"] = stdDateTime
        tradeDoc["Key"] = portfolio + "_" + symbol + "_" + side + "_" + strDateTime

        # --- Insert Database---
        database.upsert("Talent", "Trade", {"Key": tradeDoc["Key"]}, tradeDoc)
        kkwood = 0

def CountTrades():
    #
    datetime1 = datetime.datetime(2015, 1, 1)
    datetime1 = Gadget.ToUTCDateTime(datetime1)
    datetime2 = datetime.datetime(2018, 5, 1)
    datetime2 = Gadget.ToUTCDateTime(datetime2)
    datetimes = Gadget.GenerateEndDayofMonth(datetime1, datetime2)
    #
    for dt in datetimes:
        # print(dt)
        datetime2 = dt
        data = database.find("Talent", "Trade", datetime1, datetime2)
        count = len(data)
        #print(str(dt) + " " + str(count))

        #
        datetime1 = dt

def PorfolioPerformence():

    portfolios = database.find("Talent", "Portfolio", query={"Disabled":0})

    #
    datetime1 = datetime.datetime(2015, 11, 1)
    datetime1 = Gadget.ToUTCDateTime(datetime1)
    datetime2 = datetime.datetime(2018, 5, 1)
    datetime2 = Gadget.ToUTCDateTime(datetime2)
    datetimes = Gadget.GenerateEndDayofMonth(datetime1, datetime2)
    #
    for dt in datetimes:
        # print(dt)
        datetime2 = dt
        #
        rets = []
        for p in portfolios:
            packageId = p["Name"]
            data = database.find("Talent", "Account", datetime1, datetime2, query={"Portfolio":packageId})
            length = len(data)
            if length > 0:
                ret = data[length-1]["Value"] / data[0]["Value"] - 1
                if np.isnan(ret):
                    print(packageId)
                rets.append(ret)

        meanRets = np.mean(rets)
        #print(str(dt) + " meanReturn " + str(meanRets))

        #
        datetime1 = dt

def TradesPerformence():
    #
    datetime1 = datetime.datetime(2015, 11, 1)
    datetime1 = Gadget.ToUTCDateTime(datetime1)
    datetime2 = datetime.datetime(2018, 5, 1)
    datetime2 = Gadget.ToUTCDateTime(datetime2)
    datetimes = Gadget.GenerateEndDayofMonth(datetime1, datetime2)
    #
    for dt in datetimes:
        # print(dt)
        datetime2 = dt
        data = database.find("Talent", "Trade", datetime1, datetime2)

        rets = []
        for trade in data:
            symbol = trade["Symbol"]
            stdDateTime = trade["StdDateTime"]
            nextWeek = stdDateTime + datetime.timedelta(days=8)
            nextMonth = stdDateTime + datetime.timedelta(days=31)
            #
            quote = database.find("Quote", symbol + "_Time_86400_Bar", stdDateTime, nextWeek)

            length = len(quote)
            if length > 0:
                ret = quote[length - 1]["Values"]["BClose"] / quote[0]["Values"]["BClose"] - 1
                if np.isnan(ret):
                    kkwood = 0
                rets.append(ret)

        meanRets = np.mean(rets)
        #print(str(dt) + " meanReturn " + str(meanRets))

        #
        datetime1 = dt

# --- 1yr /2yr 周期下， 不同标准的选拔 ---
def SelectTopTalent():
    #
    portfolios = database.find("Talent", "Portfolio", query={"Disabled": 0})
    #
    datetime1 = datetime.datetime(2017, 5, 1)
    datetime1 = Gadget.ToUTCDateTime(datetime1)
    datetime2 = datetime.datetime(2018, 6, 15)
    datetime2 = Gadget.ToUTCDateTime(datetime2)

    data = []
    for p in portfolios:
        packageId = p["Name"]
        userName = p["UserName"].strip()
        type = p["Type"]
        dataSeries = database.find("Talent", "Account", datetime1, datetime2, query={"Portfolio": packageId})
        trades = database.find("Talent", "Trade", datetime1, datetime2, query={"Portfolio": packageId})
        length = len(dataSeries)
        if length > 0:
            ret = dataSeries[length - 1]["Value"] / dataSeries[0]["Value"] - 1
            ret = ret / length * 244
            if np.isnan(ret):
                print(packageId)
            #
            stdDev = Algorithm.CalcVolatility_DataSeries(dataSeries, "Value")
            if stdDev == None:
                stdDev = 0
            else:
                annulizedStdDev = stdDev * np.sqrt(240)
            if annulizedStdDev != 0:
                sharpe = ret/annulizedStdDev
            else:
                sharpe = 0
            # " UserName "+ userName +
            #print(packageId + " Type " + str(type) + " #Days " + str(length) + " #Trades " + str(len(trades)) + " Return " + str(ret) + " AnnulizedStdDev " + str(annulizedStdDev) + " Sharpe " + str(sharpe))
            kkwood = 0
            print(userName)

        #data.append([valuation, capitalReturn, 0, 0, 0])

def PrintPositions(positions):
    print("Symbol,Qty,Price,Value,CashFlow,PL")
    for k,v in positions.items():
        print(k + " Qty " + str(v["Qty"]) + " Price " + str(v["Price"]) + " Value " + str(v["Value"]) + " CashFlow " + str(v["CashFlow"]) + " PL " + str(v["PL"]))


def CorrectAdjFactor(adjFactor, position):
    if "AdjFactor" not in position:
        position["AdjFactor"] = adjFactor
    if adjFactor != position["AdjFactor"]:
        position["Qty"] = position["Qty"] * (adjFactor / position["AdjFactor"])
        position["Cost"] = position["Cost"] * (position["AdjFactor"] / adjFactor)
        position["AdjFactor"] = adjFactor

def ValuePositions(positions, stdDateTime):
    #
    datetime1 = datetime.datetime(2016, 1, 1)
    datetime1 = Gadget.ToUTCDateTime(datetime1)
    #
    targetDate = False
    if datetime1.year == 2018 and datetime1.month == 9 and datetime1.day == 19:
        targetDate = True
    #
    totalPL = 0
    for symbol, position in positions.items():
        #
        if symbol == "300649.SZ":
            kkwood = 0

        if position["Qty"] != 0:
            quotes = database.find("Quote", symbol + "_Time_86400_Bar", datetime1, stdDateTime)
            count = len(quotes)
            if count > 0:
                quote = quotes[count - 1]
                # update price
                price = quote["Close"]
                position["Price"] = price

                # update adjusted factor && position qty
                CorrectAdjFactor(quote["AdjFactor"], position)

                # position value
                position["Value"] = price * position["Qty"]

                # position value + cum Cashflow
                position["PL"] = position["Value"] + position["CashFlow"]

            else:
                print(symbol + " Error Can't Find Price")
        #
        totalPL = totalPL + position["PL"]

    #print(str(stdDateTime) + " totalPL " + str(totalPL))
    #PrintPositions(positions)
    #print(" *** ")
    kkwood = 0
    return totalPL

def StockList():
    trades = database.find("Instruments", "Stock")
    symbols = []
    for trade in trades:
        symbol = trade["Symbol"]
        symbols.append(symbol)
    return symbols

def StatsTalentTradeCap():
    talentList = []
    talentList.append(str(11175))
    talentList.append(str(11373))
    talentList.append(str(12195))
    talentList.append(str(12304))
    talentList.append(str(12419))
    talentList.append(str(11370))
    talentList.append(str(12036))
    talentList.append(str(11313))
    talentList.append(str(12404))
    talentList.append(str(12495))
    talentList.append(str(12341))
    talentList.append(str(12103))
    talentList.append(str(12334))
    talentList.append(str(12308))
    talentList.append(str(12230))
    talentList.append(str(11500))
    talentList.append(str(12279))
    talentList.append(str(11354))
    talentList.append(str(11147))
    talentList.append(str(11303))
    talentList.append(str(12340))
    talentList.append(str(12126))
    talentList.append(str(11556))
    talentList.append(str(11251))
    talentList.append(str(12044))
    talentList.append(str(11738))
    caps = []
    list_symbol = []
    for i in range(len(talentList)):
        packageId = talentList[i]
        datetime1 = datetime.datetime(2017, 5, 1)
        datetime1 = Gadget.ToUTCDateTime(datetime1)
        datetime2 = datetime.datetime(2018, 5, 1)
        datetime2 = Gadget.ToUTCDateTime(datetime2)
        #
        trades = database.find("Talent", "Trade", datetime1, datetime2, query={"Portfolio": packageId})

        positions = {}
        holdingPeriods = []
        tradeProfits = []
        statistics = []
        currentDateTime = None

        for trade in trades:
            # print(trade["Symbol"] + " " + str(trade["StdDateTime"]) + " " + trade["Side"] + " Qty " + str(trade["Qty"]) + " Price " + str(trade["Price"]))

            #
            tradeDateTime = trade["StdDateTime"]
            symbol = trade["Symbol"]

            beginDateTime = tradeDateTime - datetime.timedelta(days=25)
            quotes = database.find("Quote", symbol + "_Time_86400_Bar", beginDateTime, tradeDateTime)
            quotes2 = database.find("Quote", symbol + "_Time_86400_Bar", datetime.datetime(2017, 5, 1), datetime.datetime(2018, 5, 1))
            length = len(quotes)
            q = quotes2[length - 1]
            p = quotes2[0]
            cap = (q["Close"] * q["Values"]["TotalShares"] + p["Close"] * p["Values"]["TotalShares"])/2
            if symbol not in list_symbol:
                list_symbol.append(symbol)
                caps.append(cap)

    #print(caps)
    IO.WriteListToFile("D:\\cap.csv", caps)
            # list.append( symbol + ","+ str(cap) + "," + tradeDateTime])
        #IO.WriteList2ToFile("D:\\" + packageId + ".csv", list)

def StatsVolume():
    symbol = StockList()
    average_volume = []
    for i in range(len(symbol)):
        stock_id = symbol[i]
        datetime1 = datetime.datetime(2017, 5, 1)
        datetime1 = Gadget.ToUTCDateTime(datetime1)
        datetime2 = datetime.datetime(2018, 5, 1)
        datetime2 = Gadget.ToUTCDateTime(datetime2)
        #print(time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(time.time())))
        money = []
        quotes = database.find("Quote", stock_id + "_Time_86400_Bar", datetime1, datetime2)
        if len(quotes) == 0:
            a = 1
        for quote in quotes:
            trade_volume = quote["Money"]
            #print(trade_volume)
            if trade_volume != np.nan and trade_volume > 0:
               money.append(trade_volume)
        if len(money) != 0:
            average_volume.append([stock_id, sum(money) / len(money)])





    IO.WriteList2ToFile("D:\\AverageVolume.csv", average_volume)
            # list.append( symbol + ","+ str(cap) + "," + tradeDateTime])
        #IO.WriteList2ToFile("D:\\" + packageId + ".csv", list)

def GetStStocks():
    trades = database.find("Instruments", "Stock")
    symbols_st_stocks = []
    for trade in trades:
        symbol = trade["Description"]
        if "ST" in symbol or "*" in symbol:
            #print(symbol)
            symbols_st_stocks.append(trade["Symbol"])
    #print(symbols_st_stocks)
    return symbols_st_stocks

def NetValueCurve(packageIds, datetime1,datetime2,tradingCost=0, useAvgPrice=False):

    print(datetime1)
    dcsi300_1 = database.GetDataSeries("000300.SH", dataType="DailyBar", instrumentType="Index",datetime1=datetime1, datetime2=datetime2)

    filter ={}
    filter["StdDateTime"] = {}
    filter["StdDateTime"]["$gte"] = datetime1
    filter["StdDateTime"]["$lte"] = datetime2
    filter["Symbol"] = "000001.SH"
    sz_index = database.Find("Index", "DailyBar", filter)


    #sz_index = database.find("Index", "000001.SH_Time_86400_Bar", datetime1, datetime2)
    dates = []
    index = []
    index1 = []
    net_start = 100000000 * len(packageIds)
    cash = 100000000 * len(packageIds)
    netvalues = []

    package_id_list = []
    for package_id in packageIds:
        package_id_list.append({"Portfolio": package_id})

    filter = {"$or": package_id_list}
    trades = database.find("Talent", "Trade", datetime1, datetime2, query=filter)

    positions = {}

    for i in range(len(sz_index)):
        dates.append(sz_index[i]["StdDateTime"])
        index1.append(sz_index[i]["Close"]/sz_index[0]["Close"])



    i = 0
    j = 0
    while i < len(dates):
        dailyDate = dates[i]
        #print(" *** " + str(dailyDate) + " ***")
        for symbol in positions:
            quotes = database.find("Quote", symbol + "_Time_86400_Bar", dates[i] - datetime.timedelta(days=100),
                                   dates[i])
            quote = quotes[len(quotes) - 1]
            quote_lastday = quotes[len(quotes) - 2]
            positions[symbol]["AdjFactor"] = quote["AdjFactor"] / quote_lastday["AdjFactor"]
            positions[symbol]["Qty"] = positions[symbol]["Qty"] * positions[symbol]["AdjFactor"]
            #if positions[symbol]["AdjFactor"] != 1:
              #  print(symbol)
               # print(positions[symbol]["AdjFactor"])
               # print(quote_lastday["AdjFactor"])
                #print(quote["AdjFactor"])

        while j < len(trades) and dates[i] >= trades[j]["StdDateTime"]:
            tradeDate = trades[j]["StdDateTime"]
            #print("Trade" + str(tradeDate) )
            symbol = trades[j]["Symbol"]
            if symbol not in positions:
                doc = {}
                doc["Symbol"] = symbol
                doc["Qty"] = 0
                doc["Price"] = trades[j]["Price"]
                doc["CashFlow"] = 0
                doc["AdjFactor"] = 1
                positions[symbol] = doc

            if positions[symbol]["Qty"] + trades[j]["Qty"] < 0:
                qty = positions[symbol]["Qty"]
                positions[symbol]["Qty"] = 0
                cashflow = qty * trades[j]["Price"] - abs(qty * trades[j]["Price"] * tradingCost)
            else:
                positions[symbol]["Qty"] = positions[symbol]["Qty"] + trades[j]["Qty"]
                cashflow = trades[j]["CashFlow"] - abs(trades[j]["CashFlow"] * tradingCost)

            cash = cash + cashflow
            positions[symbol]["CashFlow"] = positions[symbol]["CashFlow"] + cashflow

            j = j + 1

        stock = 0
        for symbol in positions:
            quotes = database.find("Quote", symbol + "_Time_86400_Bar", dates[i] - datetime.timedelta(days=50), dates[i])
            if quotes == None:
                print("数据未更新或者退市")
            quote = quotes[len(quotes)-1]
            stock = stock + positions[symbol]["Qty"] * quote["Close"]
        net = cash + stock
        #print(positions)
        #print(dates[i])
        print(net)
        netvalues.append(net)
        #print(netvaluecurve)
        i = i + 1

        #
        #ValuePositions(positions, dates[i])
    #MaxRetracement(netvalues, index, index1, dates)

def MaxRetracement(netvalues, index ,index1 , dates):
    # 读取sheet1中的内容，存放在data中，数据类型为DataFrame
    data = netvalues
    strdates = []
    #print(data[len(data)-1])
    index_j = np.argmax(np.maximum.accumulate(data) - data)  # 结束位置
    #print(index_j)
    index_i = np.argmax(data[:index_j])  # 开始位置
    #print(index_i)
    d = (data[index_j] - data[index_i])/ data[index_i] # 最大回撤
    for i in range(len(dates)):
        strdates.append(gadget.ToDateString(dates[i]))

    # 绘制图像
    plt.plot(strdates, data)
    plt.plot(index, color = "g")
    # 生成横纵坐标信息


    plt.plot([index_i, index_j], [data[index_i], data[index_j]], 'o', color="r", markersize=10)
    plt.show()


def GetAccount(packageId,datetime1,datetime2):

    dates = []
    package_id_list = []
    filter = {}
    filter["StdDateTime"] = {}
    filter["StdDateTime"]["$gte"] = datetime1
    filter["StdDateTime"]["$lte"] = datetime2
    filter["Symbol"] = "000300.SH"
    csi300 = database.Find("Index", "DailyBar", filter)

    for i in range(len(csi300)):
        dates.append(csi300[i]["StdDateTime"])
    #print(dates[-1])
    while dates[-1] < datetime2:
        #print(dates[-1])
        dates.append(dates[-1] + datetime.timedelta(days=1))
    packageIds = packageId
    for package_id in packageIds:
        package_id_list.append({"Portfolio": package_id})

    filter = {"$or": package_id_list}
    accounts = database.find("Talent", "Account", datetime1, datetime2, query=filter)
    net_portfolio = []
    i = 0
    while i < len(dates):
        value_portfolio = 0
        j = 0
        for account in accounts:
            if account["StdDateTime"] == dates[i]:
                value_portfolio += account["Value"]
                j += 1
        if j < len(packageIds):
            value_portfolio += (len(packageIds)-1 - j ) * 100000000

        net_portfolio.append(value_portfolio)
        print(value_portfolio)
        i = i + 1
    i=0
    Nets = {}
    for i in range(len(net_portfolio)):
        if IO.ToDateTimeString3(dates[i]) not in Nets:
            doc={}
            doc["Value"]= net_portfolio[i]
            Nets[IO.ToDateString3(dates[i])]= doc

    return(Nets)

from Core.Config import Config
config = Config()
database = config.DataBase()

#StatsTalentTradeCap()
#StockList()
#StatsVolume()
#a, daily_volume = IO.ReadCSVFile("D:\\AverageVolume.csv")
st_list = GetStStocks()
threshold = 200000000
kkwood = 0
packageId_16 = ["12126", "11303", "12230","11147","12340","12044","11354","11556","12495","11500","12279","11370","12308","11738","12334","12341"]
packageId_26 = ["12126","11303","12230","11147", "12340", "12044", "11354", "11556", "12495", "11500", "12279", "11370",
"12308","11738", "12334", "12341", "12304", "11313","12404", "12103","11175","11251","12419","11373","12036","12195"]
datetime1 = datetime.datetime(2017, 5, 2)
datetime1 = Gadget.ToUTCDateTime(datetime1)
datetime2 = datetime.datetime(2018, 11, 30)
datetime2 = Gadget.ToUTCDateTime(datetime2)

#BacktestTalentsTrade()
#NetValueCurve(packageId_16,datetime1,datetime2)
#GetAccount(packageId_26,datetime1,datetime2)
#SelectTopTalent()


